/*****************************************************************************
* Project:
* All project
* Copyright(C) 2020-2021 Shenju Co.Ltd, All rights reserved.
* Description:
* All code is genrated by yangyang
* Author:
* yangyang
****************************************************************************/
#include "oal_type.h"
#include "oal_thread.h"
#include "oal_mem.h"

#include <Windows.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tick
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void OAL_sleep(uint64_t milliseconds)
{
	Sleep((DWORD)milliseconds);
}
unsigned int OAL_get_tick_count()
{
	return GetTickCount();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// mutex & sempone
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OAL_SEM OAL_sem_create_binary()
{
	return CreateSemaphore(0, 0, 1, 0);
}
OAL_SEM OAL_sem_create_count(int32_t initcount, int32_t maxcount)
{
	return CreateSemaphore(0, initcount, maxcount, 0);
}

OAL_RESULT OAL_sem_destroy(OAL_SEM* sem)
{
	if (*sem)
		CloseHandle(*sem);
	*sem = 0;
	return OAL_SUCCESS;
}

OAL_RESULT OAL_sem_wait(OAL_SEM* sem)
{
	if (WAIT_OBJECT_0 == WaitForSingleObject(*sem, INFINITE))
	{
		return OAL_SUCCESS;
	}
	return OAL_FAILED;
}

OAL_RESULT OAL_sem_wait_timeout(OAL_SEM* sem, uint32_t milliseconds)
{
	if (WAIT_OBJECT_0 == WaitForSingleObject(*sem, milliseconds))
	{
		return OAL_SUCCESS;
	}
	return OAL_FAILED;
}

void OAL_sem_post(OAL_SEM* sem)
{
	ReleaseSemaphore(*sem, 1, 0);
}

OAL_MUTEX OAL_mutex_create()
{
	return CreateMutex(0, FALSE, 0);
}

OAL_RESULT OAL_mutex_destroy(OAL_MUTEX* mutex)
{
	if (*mutex)
		CloseHandle(*mutex);
    *mutex = 0;
	return OAL_SUCCESS;
}

OAL_RESULT OAL_mutex_lock(OAL_MUTEX* mutex)
{
    if(*mutex){
        WaitForSingleObject(*mutex, INFINITE);
        return OAL_SUCCESS;
    }
    return OAL_FAILED;
}

void OAL_mutex_unlock(OAL_MUTEX* mutex)
{
    if(*mutex){
        ReleaseMutex(*mutex);
    }
}

void OAL_enter_critical_section()
{

}

void OAL_exit_critical_section()
{
	
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// thread 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OAL_start_scheduler()
{

}

static DWORD myThreadFunction(void *data)
{
	OAL_THREAD_HANDLE *pHandle = (OAL_THREAD_HANDLE *)data;
	pHandle->pFunc(pHandle->pUserParameter);
	return 0;
}

OAL_THREAD OAL_thread_create(OAL_THREAD_START_ROUTINE pFun, void* pUserParameter, char* name, OAL_THREAD_PRIORITY pri, unsigned int stackSize)
{
	name = name;
	pri = pri;
	stackSize = stackSize;
	OAL_THREAD_HANDLE *pHandle = (OAL_THREAD_HANDLE *)OAL_malloc(sizeof(OAL_THREAD_HANDLE));
	if (pHandle)
	{
		unsigned long aa = 0;
		pHandle->pFunc = pFun;
		pHandle->pUserParameter = pUserParameter;
		pHandle->exitSem = OAL_sem_create_binary();
		pHandle->handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThreadFunction, pHandle, 0, &aa);
	}
	
	return pHandle;
}

void OAL_thread_join(OAL_THREAD thread)
{
	if (thread)
	{
		OAL_THREAD_HANDLE *pHandle = (OAL_THREAD_HANDLE *)thread;
		OAL_sem_post(&pHandle->exitSem);
		if (WAIT_OBJECT_0 == WaitForSingleObject(pHandle->handle, INFINITE))
		{
			CloseHandle(pHandle->handle);
		}
		OAL_sem_destroy(&pHandle->exitSem);
		OAL_free(thread);
	}
}

OAL_RESULT OAL_thread_wait_join_ex(OAL_THREAD thread, uint32_t milliseconds)
{
	OAL_THREAD_HANDLE* pHandle = (OAL_THREAD_HANDLE*)thread;
	return OAL_sem_wait_timeout(&pHandle->exitSem, milliseconds);
}

OAL_RESULT OAL_thread_priority(OAL_THREAD thread, int32_t nPriority)
{
	if (thread)
	{
		int pri;
		switch(nPriority)
		{
		case OAL_THREAD_PRIORITY_NORMAL:
			pri = THREAD_PRIORITY_NORMAL;
			break;
		case OAL_THREAD_PRIORITY_HIGH:
			pri = THREAD_PRIORITY_HIGHEST;
			break;
		case OAL_THREAD_PRIORITY_LOW_HIGH:
			pri = THREAD_PRIORITY_ABOVE_NORMAL;
			break;
		case OAL_THREAD_PRIORITY_LOW_NORMAL:
			pri = THREAD_PRIORITY_BELOW_NORMAL;
			break;
		case OAL_THREAD_PRIORITY_LOW:
			pri = THREAD_PRIORITY_LOWEST;
			break;
		}
		if (SetThreadPriority(thread, nPriority))
			return OAL_SUCCESS;
	}

	return OAL_FAILED;
}
